﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using InkFx.ConfuserEx.Properties;
using InkFx.ConfuserEx.Utils;

namespace InkFx.ConfuserEx
{
    internal class ConfuserExHelper
    {
        public static bool ConfuseAssembly(string file)
        {
            if (!File.Exists(file)) return false;
            if (!file.EndsWith(".dll", StringComparison.CurrentCultureIgnoreCase) && !file.EndsWith(".exe", StringComparison.CurrentCultureIgnoreCase)) return false;

            Tools.LogInfo(string.Format("混淆的文件 {0} 开始", file));

            //生成混淆方案
            FileInfo fileInfo = new FileInfo(file);
            string targetFolder = string.Format(@"{0}\ConfuserEx_{1}\", fileInfo.DirectoryName, fileInfo.Name);
            string targetPath = string.Format(@"{0}\{1}", targetFolder, fileInfo.Name);
            string xmlPath = InitConfuserExXml(file, targetFolder);
            Tools.LogOK(string.Format("生成混淆方案 {0} 成功", xmlPath));

            //调用ConfuserEx
            Tools.LogInfo("开始执行混淆...");
            string result = CmdConfuserEx(xmlPath);
            Tools.LogInfo("执行混淆结束...");
            Tools.LogInfo("记录混淆日志: \r\n" + result);
            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine();

            if (!File.Exists(targetPath))
            {
                Tools.LogError(string.Format("混淆后的文件 {0} 不存在, 可能混淆发生了失败", targetPath));
                FileHelper.WriteAllText(targetPath + ".err.log", result, Encoding.UTF8);
                return false;
            }



            FileHelper.DeleteFile(xmlPath);
            string newFile_dir = FileHelper.GetParentFolderPath(targetPath);
            string newPath_pdb = FileHelper.FormatFullPath(newFile_dir + @"\" + Path.GetFileNameWithoutExtension(targetPath) + ".pdb");
            string newPath_xml = FileHelper.FormatFullPath(newFile_dir + @"\" + Path.GetFileNameWithoutExtension(targetPath) + ".xml");

            string oldFile_dir = FileHelper.GetParentFolderPath(file);
            string oldPath_pdb = FileHelper.FormatFullPath(oldFile_dir + @"\" + Path.GetFileNameWithoutExtension(targetPath) + ".pdb");
            string oldPath_xml = FileHelper.FormatFullPath(oldFile_dir + @"\" + Path.GetFileNameWithoutExtension(targetPath) + ".xml");



            FileInfo newFile_lib = new FileInfo(targetPath);
            FileInfo newFile_pdb = new FileInfo(newPath_pdb);
            FileInfo newFile_xml = new FileInfo(newPath_xml);
            if (newFile_lib.Exists)
            {
                File.Delete(file);
                File.Copy(newFile_lib.FullName, file, true);
                Tools.LogOK(string.Format("拷贝混淆后的 {0} 到原目录", newFile_lib.FullName));

                if (newFile_pdb.Exists) { File.Delete(oldPath_pdb); File.Copy(newFile_pdb.FullName, oldPath_pdb, true); Tools.LogOK(string.Format("拷贝混淆后的 {0} 到原目录", newFile_pdb.FullName)); } //拷贝混淆后的 pdb 文件
                if (newFile_xml.Exists) { File.Delete(oldPath_xml); File.Copy(newFile_xml.FullName, oldPath_xml, true); Tools.LogOK(string.Format("拷贝混淆后的 {0} 到原目录", newFile_xml.FullName)); } //拷贝混淆后的 xml 文件
                
                FileHelper.DeleteFolder(targetFolder, true);
                Tools.LogOK(string.Format("删除临时目录 {0} ", targetFolder));
                return true;
            }
            return false;
        }


        private static string InitConfuserExXml(string file, string targetFolder)
        {
            if (!File.Exists(file)) return string.Empty;
            FileInfo fileInfo = new FileInfo(file);
            FileHelper.DeleteFolder(targetFolder, true);
            FileHelper.CreateFolder(targetFolder);

            var exeFolder = FileHelper.GetParentFolderPath(typeof(ConfuserExHelper).Assembly.Location);
            string xmlTempPath = FileHelper.FormatFullPath(string.Format(@"{0}\InkFx.ConfuserEx.Template.xml", exeFolder));
            //throw new Exception(FileHelper.ExistFile(xmlTempPath) + "| " + xmlTempPath); //调试BUG用
            string xmlTemp = FileHelper.ReadAllText(xmlTempPath, Encoding.UTF8);
            if (string.IsNullOrWhiteSpace(xmlTemp)) xmlTemp = Resources.InkFx_ConfuserEx_Template; //如果用户没有自定义模版文件, 则使用内置的 模版文件


            string xml = xmlTemp
                .Replace("{RndPrefix}", Guid.NewGuid().ToString().Trim('[', ']', '{', '}').Replace("-", string.Empty).Substring(3, 5))
                .Replace("{RefGuid}", Guid.NewGuid().ToString())
                .Replace("{FileFolder}", fileInfo.DirectoryName.TrimEnd('\\', '/'))
                .Replace("{FileName}", fileInfo.Name)
                .Replace("{TargetFolder}", targetFolder.TrimEnd('\\', '/'))
                //.Replace("", "")
                //.Replace("", "")
                ;

            string xmlPath = FileHelper.FormatFullPath(string.Format(@"{0}\ConfuserEx_{1}.crproj", targetFolder, fileInfo.Name));
            File.WriteAllText(xmlPath, xml, Encoding.UTF8);
            return File.Exists(xmlPath) ? xmlPath : string.Empty;
        }
        private static string CmdConfuserEx(string xmlPath)
        {
            var exeFolder = FileHelper.GetParentFolderPath(typeof(ConfuserExHelper).Assembly.Location);
            string exePath = FileHelper.FormatFullPath((ConfigurationManager.AppSettings["ConfuserExPath"] ?? string.Empty).Trim());
            if (!FileHelper.ExistFile(exePath))
            {
                exePath = FileHelper.FormatFullPath(string.Format(@"{0}\Confuser.CLI.exe", exeFolder));
            }
            if (!FileHelper.ExistFile(exePath))
            {
                exePath = FileHelper.FormatFullPath(string.Format(@"{0}\ConfuserEx\Confuser.CLI.exe", exeFolder));
            }

            Console.WriteLine("执行命令:");
            Console.WriteLine("---------------------------------------------");
            Console.WriteLine(string.Format("{0} -n \"{1}\"", exePath, xmlPath));
            Console.WriteLine("---------------------------------------------");


            var result = new StringBuilder();
            Process process = new Process();
            process.StartInfo.FileName = exePath;
            process.StartInfo.Arguments = string.Format("-n \"{0}\" ", xmlPath);
            process.StartInfo.CreateNoWindow = true;   
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.RedirectStandardError = true;
            process.OutputDataReceived += (s, e) => { Console.WriteLine(e.Data); result.AppendLine(e.Data); };
            process.ErrorDataReceived += (s, e) => { Console.WriteLine(e.Data); result.AppendLine(e.Data); };
            process.Start();

            //process.StandardInput.WriteLine(string.Format("\"{0}\" \"{1}\"", exePath, xmlPath));
            //process.StandardInput.WriteLine("exit");
            process.BeginOutputReadLine();
            process.BeginErrorReadLine();
            process.WaitForExit();
            Console.WriteLine("---------------------------------------------");
            return result.ToString();
        }



    }
}
